1 module eastasianwidth; 2 3 public import eastasianwidth.eastasianwidth; 4 5 import std.traits; 6 7 /// 8 enum AmbiguousCharWidth : bool { 9 narrow, 10 wide 11 } 12 13 /// returns monospace display width of a character 14 size_t displayWidth(T)(T ch, AmbiguousCharWidth acw = AmbiguousCharWidth.narrow) 15 if (isSomeChar!T) { 16 auto prop = eastAsianWidth(ch); 17 if (prop == EastAsianWidthProperty.F || prop == EastAsianWidthProperty.W) { 18 return 2; 19 } else if (prop == EastAsianWidthProperty.A) { 20 return (acw == AmbiguousCharWidth.narrow) ? 1 : 2; 21 } else { 22 return 1; 23 } 24 } 25 26 /// returns monospace display width of a string 27 size_t displayWidth(T)(T str, AmbiguousCharWidth acw = AmbiguousCharWidth.narrow) 28 if (isSomeString!T) { 29 size_t width; 30 foreach (dchar ch; str) { 31 width += displayWidth(ch, acw); 32 } 33 return width; 34 } 35 36 /// 37 @safe pure @nogc unittest { 38 assert(displayWidth("あいうえお") == 10); 39 40 // '☆' is Ambiguous characters 41 assert(displayWidth('☆') == 1); 42 assert(displayWidth('☆', AmbiguousCharWidth.wide) == 2); 43 assert(displayWidth("☆D言語くん☆") == 11); 44 assert(displayWidth("☆D言語くん☆", AmbiguousCharWidth.wide) == 13); 45 46 assert(eastAsianWidth('A') == EastAsianWidthProperty.F); // Fullwidth 47 assert(eastAsianWidth('ア') == EastAsianWidthProperty.H); // Halfwidth 48 assert(eastAsianWidth('ア') == EastAsianWidthProperty.W); // Wide 49 assert(eastAsianWidth('A') == EastAsianWidthProperty.Na); // Narrow 50 assert(eastAsianWidth('☆') == EastAsianWidthProperty.A); // Ambiguous 51 assert(eastAsianWidth('À') == EastAsianWidthProperty.N); // Neutral 52 } 53 54 @safe pure @nogc nothrow unittest { 55 assert(eastAsianWidth('A') == EastAsianWidthProperty.F); 56 assert(eastAsianWidth('!') == EastAsianWidthProperty.F); 57 assert(eastAsianWidth('₩') == EastAsianWidthProperty.F); 58 59 assert(eastAsianWidth('ア') == EastAsianWidthProperty.H); 60 assert(eastAsianWidth('←') == EastAsianWidthProperty.H); 61 assert(eastAsianWidth('₩') == EastAsianWidthProperty.H); 62 63 assert(eastAsianWidth('ア') == EastAsianWidthProperty.W); 64 assert(eastAsianWidth('𛀀') == EastAsianWidthProperty.W); 65 assert(eastAsianWidth('뀀') == EastAsianWidthProperty.W); 66 67 assert(eastAsianWidth('A') == EastAsianWidthProperty.Na); 68 assert(eastAsianWidth('¢') == EastAsianWidthProperty.Na); 69 assert(eastAsianWidth('⟦') == EastAsianWidthProperty.Na); 70 71 assert(eastAsianWidth('¿') == EastAsianWidthProperty.A); 72 assert(eastAsianWidth('Σ') == EastAsianWidthProperty.A); 73 assert(eastAsianWidth('℃') == EastAsianWidthProperty.A); 74 75 assert(eastAsianWidth('©') == EastAsianWidthProperty.N); 76 assert(eastAsianWidth('À') == EastAsianWidthProperty.N); 77 assert(eastAsianWidth('ي') == EastAsianWidthProperty.N); 78 } 79 80 @safe pure @nogc nothrow unittest { 81 assert(displayWidth('A') == 2); 82 assert(displayWidth('!') == 2); 83 assert(displayWidth('₩') == 2); 84 85 assert(displayWidth('ア') == 1); 86 assert(displayWidth('←') == 1); 87 assert(displayWidth('₩') == 1); 88 89 assert(displayWidth('ア') == 2); 90 assert(displayWidth('𛀀') == 2); 91 assert(displayWidth('뀀') == 2); 92 93 assert(displayWidth('A') == 1); 94 assert(displayWidth('¢') == 1); 95 assert(displayWidth('⟦') == 1); 96 97 assert(displayWidth('¿') == 1); 98 assert(displayWidth('Σ') == 1); 99 assert(displayWidth('℃') == 1); 100 101 assert(displayWidth('©') == 1); 102 assert(displayWidth('À') == 1); 103 assert(displayWidth('ي') == 1); 104 } 105 106 @safe pure @nogc nothrow unittest { 107 assert(displayWidth('A', AmbiguousCharWidth.wide) == 2); 108 assert(displayWidth('!', AmbiguousCharWidth.wide) == 2); 109 assert(displayWidth('₩', AmbiguousCharWidth.wide) == 2); 110 111 assert(displayWidth('ア', AmbiguousCharWidth.wide) == 1); 112 assert(displayWidth('←', AmbiguousCharWidth.wide) == 1); 113 assert(displayWidth('₩', AmbiguousCharWidth.wide) == 1); 114 115 assert(displayWidth('ア', AmbiguousCharWidth.wide) == 2); 116 assert(displayWidth('𛀀', AmbiguousCharWidth.wide) == 2); 117 assert(displayWidth('뀀', AmbiguousCharWidth.wide) == 2); 118 119 assert(displayWidth('A', AmbiguousCharWidth.wide) == 1); 120 assert(displayWidth('¢', AmbiguousCharWidth.wide) == 1); 121 assert(displayWidth('⟦', AmbiguousCharWidth.wide) == 1); 122 123 assert(displayWidth('¿', AmbiguousCharWidth.wide) == 2); 124 assert(displayWidth('Σ', AmbiguousCharWidth.wide) == 2); 125 assert(displayWidth('℃', AmbiguousCharWidth.wide) == 2); 126 127 assert(displayWidth('©', AmbiguousCharWidth.wide) == 1); 128 assert(displayWidth('À', AmbiguousCharWidth.wide) == 1); 129 assert(displayWidth('ي', AmbiguousCharWidth.wide) == 1); 130 } 131 132 @safe pure @nogc unittest { 133 assert(displayWidth("D-Man") == 5); 134 assert(displayWidth("D-Man", AmbiguousCharWidth.wide) == 5); 135 assert(displayWidth("「D言語くん」") == 12); 136 assert(displayWidth("「D言語くん」", AmbiguousCharWidth.wide) == 12); 137 assert(displayWidth("Ελληνικά") == 8); 138 assert(displayWidth("Ελληνικά", AmbiguousCharWidth.wide) == 15); 139 assert(displayWidth("اللغة العربية") == 13); 140 assert(displayWidth("اللغة العربية", AmbiguousCharWidth.wide) == 13); 141 assert(displayWidth("ლ(́⊙ɛ⊙`)ლ") == 9); 142 assert(displayWidth("ლ(́⊙ɛ⊙`)ლ", AmbiguousCharWidth.wide) == 12); 143 }